namespace DotNetNuke.Security
{
    using DotNetNuke.Common;
    using DotNetNuke.Common.Utilities;
    using DotNetNuke.Entities.Modules;
    using DotNetNuke.Entities.Portals;
    using DotNetNuke.Entities.Users;
    using DotNetNuke.Security.Permissions;
    using DotNetNuke.Services.Log.EventLog;
    using Microsoft.VisualBasic;
    using Microsoft.VisualBasic.CompilerServices;
    using System;
    using System.IO;
    using System.Runtime.CompilerServices;
    using System.Security.Cryptography;
    using System.Text;
    using System.Text.RegularExpressions;
    using System.Web;
    using System.Web.Security;    

    public class PortalSecurity
    {
        /// -----------------------------------------------------------------------------
        /// <summary>
        /// This function converts a byte array to a hex string
        /// </summary>
        /// <param name="bytes">An array of bytes</param>
        /// <returns>A string representing the hex converted value</returns>
        /// <remarks>
        /// This is a private function that is used internally by the CreateKey function
        /// </remarks>
        /// <history>
        /// </history>
        /// -----------------------------------------------------------------------------
        private string BytesToHexString(byte[] bytes)
        {
            StringBuilder hexString = new StringBuilder(0x40);
            int refIntHelperL0 = bytes.Length - 1;
            for (int counter = 0; counter <= refIntHelperL0; counter++)
            {
                hexString.Append(string.Format("{0:X2}", bytes[counter]));
            }
            return hexString.ToString();
        }

        /// -----------------------------------------------------------------------------
        /// <summary>
        /// This function creates a random key
        /// </summary>
        /// <param name="numBytes">This is the number of bytes for the key</param>
        /// <returns>A random string</returns>
        /// <remarks>
        /// This is a public function used for generating SHA1 keys 
        /// </remarks>
        /// <history>
        /// </history>
        /// -----------------------------------------------------------------------------
        public string CreateKey(int numBytes)
        {
            RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider();
            byte[] buff = new byte[(numBytes - 1) + 1];
            rng.GetBytes(buff);
            return this.BytesToHexString(buff);
        }

        public string Decrypt(string strKey, string strData)
        {
            string strValue = "";
            if (strKey != "")
            {
                int refIntHelperL0 = Strings.Len(strKey);
                if (refIntHelperL0 < 0x10)
                {
                    strKey = strKey + Strings.Left("XXXXXXXXXXXXXXXX", 0x10 - Strings.Len(strKey));
                }
                else if (refIntHelperL0 > 0x10)
                {
                    strKey = Strings.Left(strKey, 0x10);
                }
                byte[] byteKey = Encoding.UTF8.GetBytes(Strings.Left(strKey, 8));
                byte[] byteVector = Encoding.UTF8.GetBytes(Strings.Right(strKey, 8));
                byte[] byteData = new byte[strData.Length + 1];
                try
                {
                    byteData = Convert.FromBase64String(strData);
                }
                catch (Exception exception1)
                {
                    
                    strValue = strData;
                    
                }
                if (strValue == "")
                {
                    try
                    {
                        DESCryptoServiceProvider objDES = new DESCryptoServiceProvider();
                        MemoryStream objMemoryStream = new MemoryStream();
                        CryptoStream objCryptoStream = new CryptoStream(objMemoryStream, objDES.CreateDecryptor(byteKey, byteVector), CryptoStreamMode.Write);
                        objCryptoStream.Write(byteData, 0, byteData.Length);
                        objCryptoStream.FlushFinalBlock();
                        strValue = Encoding.UTF8.GetString(objMemoryStream.ToArray());
                    }
                    catch (Exception exception2)
                    {
                        ProjectData.SetProjectError(exception2);
                        strValue = "";
                        
                    }
                }
                return strValue;
            }
            return strData;
        }

        public string Encrypt(string strKey, string strData)
        {
            if (strKey != "")
            {
                int refIntHelperL0 = Strings.Len(strKey);
                if (refIntHelperL0 < 0x10)
                {
                    strKey = strKey + Strings.Left("XXXXXXXXXXXXXXXX", 0x10 - Strings.Len(strKey));
                }
                else if (refIntHelperL0 > 0x10)
                {
                    strKey = Strings.Left(strKey, 0x10);
                }
                byte[] byteKey = Encoding.UTF8.GetBytes(Strings.Left(strKey, 8));
                byte[] byteVector = Encoding.UTF8.GetBytes(Strings.Right(strKey, 8));
                byte[] byteData = Encoding.UTF8.GetBytes(strData);
                DESCryptoServiceProvider objDES = new DESCryptoServiceProvider();
                MemoryStream objMemoryStream = new MemoryStream();
                CryptoStream objCryptoStream = new CryptoStream(objMemoryStream, objDES.CreateEncryptor(byteKey, byteVector), CryptoStreamMode.Write);
                objCryptoStream.Write(byteData, 0, byteData.Length);
                objCryptoStream.FlushFinalBlock();
                return Convert.ToBase64String(objMemoryStream.ToArray());
            }
            return strData;
        }

        /// -----------------------------------------------------------------------------
        /// <summary>
        /// This function uses Regex search strings to remove HTML tags which are 
        /// targeted in Cross-site scripting (XSS) attacks.  This function will evolve
        /// to provide more robust checking as additional holes are found.
        /// </summary>
        /// <param name="strInput">This is the string to be filtered</param>
        /// <returns>Filtered UserInput</returns>
        /// <remarks>
        /// This is a private function that is used internally by the InputFilter function
        /// </remarks>
        /// <history>
        /// [Joe Brinkman] 	8/15/2003	Created Bug #000120
        /// </history>
        /// -----------------------------------------------------------------------------
        private string FormatDisableScripting(string strInput)
        {
            string TempInput = strInput;
            RegexOptions options = RegexOptions.Singleline | RegexOptions.IgnoreCase;
            string strReplacement = " ";
            return Regex.Replace(Regex.Replace(Regex.Replace(Regex.Replace(Regex.Replace(Regex.Replace(Regex.Replace(Regex.Replace(Regex.Replace(Regex.Replace(Regex.Replace(Regex.Replace(Regex.Replace(Regex.Replace(TempInput, "<script[^>]*>.*?</script[^><]*>", strReplacement, options), "<input[^>]*>.*?</input[^><]*>", strReplacement, options), "<object[^>]*>.*?</object[^><]*>", strReplacement, options), "<embed[^>]*>.*?</embed[^><]*>", strReplacement, options), "<applet[^>]*>.*?</applet[^><]*>", strReplacement, options), "<form[^>]*>.*?</form[^><]*>", strReplacement, options), "<option[^>]*>.*?</option[^><]*>", strReplacement, options), "<select[^>]*>.*?</select[^><]*>", strReplacement, options), "<iframe[^>]*>.*?</iframe[^><]*>", strReplacement, options), "<ilayer[^>]*>.*?</ilayer[^><]*>", strReplacement, options), "<form[^>]*>", strReplacement, options), "</form[^><]*>", strReplacement, options), "javascript:", strReplacement, options), "vbscript:", strReplacement, options);
        }

        /// -----------------------------------------------------------------------------
        /// <summary>
        /// This filter removes CrLf characters and inserts br
        /// </summary>
        /// <param name="strInput">This is the string to be filtered</param>
        /// <returns>Filtered UserInput</returns>
        /// <remarks>
        /// This is a private function that is used internally by the InputFilter function
        /// </remarks>
        /// <history>
        /// [Joe Brinkman] 	8/15/2003	Created Bug #000120
        /// </history>
        /// -----------------------------------------------------------------------------
        private string FormatMultiLine(string strInput)
        {
            return strInput.Replace("\r\n", "<br>").Replace("\r", "<br>");
        }

        /// -----------------------------------------------------------------------------
        /// <summary>
        /// This function verifies raw SQL statements to prevent SQL injection attacks 
        /// and replaces a similar function (PreventSQLInjection) from the Common.Globals.vb module
        /// </summary>
        /// <param name="strSQL">This is the string to be filtered</param>
        /// <returns>Filtered UserInput</returns>
        /// <remarks>
        /// This is a private function that is used internally by the InputFilter function
        /// </remarks>
        /// <history>
        /// [Joe Brinkman] 	8/15/2003	Created Bug #000121
        /// [Tom Lucas]     3/8/2004    Fixed   Bug #000114 (Aardvark)
        /// </history>
        /// -----------------------------------------------------------------------------
        private string FormatRemoveSQL(string strSQL)
        {
            string strCleanSQL = strSQL;
            if (strSQL == null)
            {
                return strCleanSQL;
            }
            Array BadCommands = Strings.Split(";,--,create,drop,select,insert,delete,update,union,sp_,xp_", ",", -1, CompareMethod.Binary);
            int refIntHelperL0 = BadCommands.Length - 1;
            for (int intCommand = 0; intCommand <= refIntHelperL0; intCommand++)
            {
                strCleanSQL = Regex.Replace(strCleanSQL, Convert.ToString(RuntimeHelpers.GetObjectValue(BadCommands.GetValue(intCommand))), " ", RegexOptions.IgnoreCase);
            }
            return Strings.Replace(strCleanSQL, "'", "''", 1, -1, CompareMethod.Binary);
        }

        /// -----------------------------------------------------------------------------
        /// <summary>
        /// Verifies edit permissions on a module
        /// </summary>
        /// <param name="objModulePermissions"></param>
        /// <returns></returns>
        /// <remarks>
        /// </remarks>
        /// <history>
        /// [VMasanas]	07/12/2004	Changed to remove the check: if not visible not editable. 
        /// Was causing trouble when inheritviewpermissions from tab was checked.
        /// </history>
        /// -----------------------------------------------------------------------------
        public static bool HasEditPermissions(ModulePermissionCollection objModulePermissions)
        {
            return ModulePermissionController.HasModulePermission(objModulePermissions, "EDIT");
        }

        public static bool HasEditPermissions(int ModuleId)
        {
            ModulePermissionController objModulePermissionController = new ModulePermissionController();
            return HasEditPermissions(objModulePermissionController.GetModulePermissionsCollectionByModuleID(ModuleId));
        }

        /// -----------------------------------------------------------------------------
        /// <summary>
        /// Determines is user has the necessary permissions to access the an item with the
        /// designated AccessLevel.
        /// </summary>
        /// <param name="AccessLevel">The SecurityAccessLevel required to access a portal module or module action.</param>
        /// <param name="PortalSettings">The PortalSettings for the current portal.</param>
        /// <param name="ModuleConfiguration">The ModuleInfo object for the associated module.</param>
        /// <param name="UserName">The Context.User.Identity.Name of the currently logged in user.</param>
        /// <returns>A boolean value indicating if the user has the necessary permissions</returns>
        /// <remarks>Every module control and module action has an associated permission level.  This
        /// function determines whether the user represented by UserName has sufficient permissions, as
        /// determined by the PortalSettings and ModuleSettings, to access a resource with the 
        /// designated AccessLevel.</remarks>
        /// <history>
        /// [jbrinkman] 	12/21/2003	Created
        /// </history>
        /// -----------------------------------------------------------------------------
        public static bool HasNecessaryPermission(SecurityAccessLevel AccessLevel, PortalSettings PortalSettings, ModuleInfo ModuleConfiguration, string UserName)
        {
            bool blnAuthorized = true;
            switch (((int) AccessLevel))
            {
                case -1:
                    return true;

                case 0:
                    if ((!IsInRole(PortalSettings.AdministratorRoleName.ToString()) & !IsInRoles(PortalSettings.ActiveTab.AdministratorRoles.ToString())) && !IsInRoles(ModuleConfiguration.AuthorizedViewRoles))
                    {
                        blnAuthorized = false;
                    }
                    return blnAuthorized;

                case 1:
                    if (!(!IsInRole(PortalSettings.AdministratorRoleName.ToString()) & !IsInRoles(PortalSettings.ActiveTab.AdministratorRoles.ToString())))
                    {
                        return blnAuthorized;
                    }
                    if (IsInRoles(ModuleConfiguration.AuthorizedViewRoles))
                    {
                        if (!HasEditPermissions(ModuleConfiguration.ModulePermissions))
                        {
                            blnAuthorized = false;
                        }
                        return blnAuthorized;
                    }
                    return false;

                case 2:
                    if (!IsInRole(PortalSettings.AdministratorRoleName.ToString()) & !IsInRoles(PortalSettings.ActiveTab.AdministratorRoles.ToString()))
                    {
                        blnAuthorized = false;
                    }
                    return blnAuthorized;

                case 3:
                    if (UserName.Length <= 0)
                    {
                        return false;
                    }
                    if (!UserController.GetCurrentUserInfo().IsSuperUser)
                    {
                        blnAuthorized = false;
                    }
                    return blnAuthorized;
            }
            return blnAuthorized;
        }

        /// -----------------------------------------------------------------------------
        /// <summary>
        /// This function determines if the Input string contains any markup.
        /// </summary>
        /// <param name="strInput">This is the string to be checked</param>
        /// <returns>True if string contains Markup tag(s)</returns>
        /// <remarks>
        /// This is a private function that is used internally by the InputFilter function
        /// </remarks>
        /// <history>
        /// [Joe Brinkman] 	8/15/2003	Created Bug #000120
        /// </history>
        /// -----------------------------------------------------------------------------
        private bool IncludesMarkup(string strInput)
        {
            RegexOptions options = RegexOptions.Singleline | RegexOptions.IgnoreCase;
            string strPattern = "<[^<>]*>";
            return Regex.IsMatch(strInput, strPattern, options);
        }

        /// -----------------------------------------------------------------------------
        /// <summary>
        /// This function applies security filtering to the UserInput string.
        /// </summary>
        /// <param name="UserInput">This is the string to be filtered</param>
        /// <param name="FilterType">Flags which designate the filters to be applied</param>
        /// <returns>Filtered UserInput</returns>
        /// <history>
        /// [Joe Brinkman] 	8/15/2003	Created Bug #000120, #000121
        /// </history>
        /// -----------------------------------------------------------------------------
        public string InputFilter(string UserInput, FilterFlag FilterType)
        {
            if (UserInput == null)
            {
                return "";
            }
            string TempInput = UserInput;
            if ((FilterType & FilterFlag.NoSQL) == FilterFlag.NoSQL)
            {
                return this.FormatRemoveSQL(TempInput);
            }
            if ((FilterType & FilterFlag.NoMarkup) == FilterFlag.NoMarkup)
            {
                if (this.IncludesMarkup(TempInput))
                {
                    TempInput = HttpUtility.HtmlEncode(TempInput);
                }
            }
            else if ((FilterType & FilterFlag.NoScripting) == FilterFlag.NoScripting)
            {
                TempInput = this.FormatDisableScripting(TempInput);
            }
            if ((FilterType & FilterFlag.MultiLine) == FilterFlag.MultiLine)
            {
                TempInput = this.FormatMultiLine(TempInput);
            }
            return TempInput;
        }

        public static bool IsInRole(string role)
        {
            UserInfo objUserInfo = UserController.GetCurrentUserInfo();
            HttpContext context = HttpContext.Current;
            return ((objUserInfo.IsSuperUser || ((((role != "") && (role != null)) && ((!context.Request.IsAuthenticated && (role == "Unauthenticated Users")) || (role == "All Users"))) ? true:false)) || (System.Web.Security.Roles.IsUserInRole(role) && (Convert.ToString(RuntimeHelpers.GetObjectValue(HttpContext.Current.Items["UserRoles"])).IndexOf(";" + role + ";") >= 0)));
        }

        public static bool IsInRoles(string roles)
        {
            if (roles != null)
            {
                HttpContext context = HttpContext.Current;
                UserInfo objUserInfo = UserController.GetCurrentUserInfo();
                foreach (string role in roles.Split(new char[] { ';' }))
                {
                    if (objUserInfo.IsSuperUser || ((((role != "") && (role != null)) && (((!context.Request.IsAuthenticated && (role == "Unauthenticated Users")) || (role == "All Users")) || IsInRole(role))) ? true: false))
                    {
                        return true;
                    }
                }
            }
            return false;
        }

        public void SignOut()
        {
            FormsAuthentication.SignOut();
            HttpContext.Current.Response.Cookies["portalaliasid"].Value = null;
            HttpContext.Current.Response.Cookies["portalaliasid"].Path = "/";
            HttpContext.Current.Response.Cookies["portalaliasid"].Expires = DateTime.Now.AddYears(-30);
            HttpContext.Current.Response.Cookies["portalroles"].Value = null;
            HttpContext.Current.Response.Cookies["portalroles"].Path = "/";
            HttpContext.Current.Response.Cookies["portalroles"].Expires = DateTime.Now.AddYears(-30);
        }

        public int UserLogin(string Username, string Password, int PortalID, string PortalName, string IP, bool CreatePersistentCookie)
        {
            UserController objUsers = new UserController();
            EventLogController objEventLog = new EventLogController();
            int UserId = -1;
            try
            {
                UserInfo objUser = objUsers.GetUserByUsername(PortalID, Username);
                if ((objUser != null) && objUser.Membership.LockedOut)
                {
                    int intTimeout = Convert.ToInt32(RuntimeHelpers.GetObjectValue(Interaction.IIf(DotNetNuke.Common.Globals.HostSettings["AutoAccountUnlockDuration"] != null, RuntimeHelpers.GetObjectValue(DotNetNuke.Common.Globals.HostSettings["AutoAccountUnlockDuration"]), -1)));
                    if (intTimeout != 0)
                    {
                        if (intTimeout == -1)
                        {
                            intTimeout = 10;
                        }
                        if (DateTime.Compare(objUser.Membership.LastLockoutDate, DateTime.Now.AddMinutes((double) (-1 * intTimeout))) < 0)
                        {
                            objUsers.UnlockUserAccount(objUser);
                            objUser.Membership.LockedOut = false;
                        }
                    }
                }
                if ((((objUser != null) && objUser.IsSuperUser) ? 1 : 0) != 0)
                {
                    DotNetNuke.Common.Globals.SetApplicationName(-1);
                }
                LogInfo objEventLogInfo = new LogInfo();
                PortalSecurity objSecurity = new PortalSecurity();
                objEventLogInfo.AddProperty("IP", IP);
                objEventLogInfo.LogPortalID = PortalID;
                objEventLogInfo.LogPortalName = PortalName;
                objEventLogInfo.LogUserName = objSecurity.InputFilter(Username, FilterFlag.NoScripting | FilterFlag.NoMarkup);
                objEventLogInfo.LogTypeKey = "LOGIN_FAILURE";
                if (Membership.ValidateUser(Username, Password))
                {
                    if (objUser == null)
                    {
                        objUser = new UserInfo();
                        objUser.Username = Username;
                        objUser.PortalID = PortalID;
                        objUser.FirstName = "";
                        objUser.LastName = "";
                        objUser.AffiliateID = Null.NullInteger;
                        objUser.IsSuperUser = false;
                        objUser.UserID = objUsers.AddUser(objUser, false);
                    }
                    if (objUser.Membership.Approved & !objUser.Membership.LockedOut)
                    {
                        UserId = objUser.UserID;
                    }
                    if (UserId != -1)
                    {
                        if (objUser.IsSuperUser)
                        {
                            objEventLogInfo.LogTypeKey = "LOGIN_SUPERUSER";
                        }
                        else
                        {
                            objEventLogInfo.LogTypeKey = "LOGIN_SUCCESS";
                        }
                    }
                }
                objEventLogInfo.LogUserID = UserId;
                objEventLog.AddLog(objEventLogInfo);
                if (UserId != -1)
                {
                    FormsAuthentication.SetAuthCookie(Username, CreatePersistentCookie);
                }
            }
            finally
            {
                DotNetNuke.Common.Globals.SetApplicationName(PortalID);
            }
            return UserId;
        }

        /// -----------------------------------------------------------------------------
        /// <summary>
        /// The FilterFlag enum determines which filters are applied by the InputFilter
        /// function.  The Flags attribute allows the user to include multiple 
        /// enumerated values in a single variable by OR'ing the individual values
        /// together.
        /// </summary>
        /// <history>
        /// [Joe Brinkman] 	8/15/2003	Created  Bug #000120, #000121
        /// </history>
        /// -----------------------------------------------------------------------------
        [Flags]
        public enum FilterFlag
        {
            MultiLine = 1,
            NoMarkup = 2,
            NoScripting = 4,
            NoSQL = 8
        }
    }
}

